package com.meta.platform.login.plus.vcode.service.impl;

import com.meta.act.app.service.*;
import com.meta.act.app.tenant.entity.TenantBase;
import com.meta.act.app.tenant.req.TenantDetailQry;
import com.meta.framework.act.entity.SysUser;
import com.meta.framework.act.model.LoginUser;
import com.meta.framework.common.constant.Constants;
import com.meta.framework.common.exception.BaseException;
import com.meta.framework.common.exception.CustomException;
import com.meta.framework.common.utils.MessageUtils;
import com.meta.framework.common.utils.SecurityUtils;
import com.meta.framework.domain.event.DomainEventPulish;
import com.meta.framework.manager.AsyncManager;
import com.meta.framework.manager.factory.AsyncFactory;
import com.meta.framework.service.TokenService;
import com.meta.framework.util.UserUtil;
import com.meta.platform.login.plus.common.vo.LoginSuccessVo;
import com.meta.platform.login.plus.security.LoginSimpleAuthenticationToken;
import com.meta.platform.login.plus.utils.VCodeUtils;
import com.meta.platform.login.plus.vcode.event.WeixinLoginUserEvent;
import com.meta.platform.login.plus.vcode.rest.req.FindPasswordCmd;
import com.meta.platform.login.plus.vcode.rest.req.RegisterCmd;
import com.meta.platform.login.plus.vcode.service.VCodeService;
import com.meta.platform.login.plus.vcode.service.VCodeUserService;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 用户业务处理
 *
 * @author pengjianfeng
 * @version 1.0
 * @date 2021/1/12 3:48 下午
 */
@Service
public class VCodeUserServiceImpl implements VCodeUserService {
    
    @Resource
    private ISysUserService iSysUserService;
    
    @Resource
    private VCodeService vCodeService;
    
    @Resource
    private TenantQryService tenantQryService;
    
    @Resource
    private AuthenticationManager authenticationManager;
    
    @Resource
    private TokenService tokenService;

    @Resource
    private ISysConfigService iSysConfigService;

    @Resource
    private DomainEventPulish publishEvent;
    
    /**
     * 账号注册
     * 
     * @param registerCmd 账号注册参数
     * @return
     */
    public LoginSuccessVo register(RegisterCmd registerCmd) {

        String phoneNumber = registerCmd.getPhoneNumber();
        if (!VCodeUtils.isPhoneNumber(phoneNumber)) {
            throw new BaseException(MessageUtils.message("user.mobile.phone.number.not.valid"));
        }
        
        if (!VCodeUtils.checkPassword(registerCmd.getPassword())) {
            throw new BaseException(MessageUtils.message("user.password.not.valid"));
        }
        
//        // 验证验证码
        boolean verify = this.vCodeService.verifyVCode(phoneNumber, registerCmd.getVCode());
        if (!verify) {
            return null;
        }

        SysUser sysUser = this.iSysUserService.selectUserByUserName(phoneNumber);
        if(Objects.isNull(sysUser)){
            String password = this.iSysConfigService.selectConfigByKey("sys.user.initPassword");
            SysUser user = new SysUser();
            user.setNickName(UserUtil.defaultUserName(phoneNumber));
            user.setUserName(phoneNumber);
            user.setPhonenumber(phoneNumber);
            user.setPassword(SecurityUtils.encryptPassword(password));
            user.setTenantId(1L);

            this.iSysUserService.insertUser(user);
            sysUser = user;
        }
        // 获取域角色

        // 注册成功后，直接登录
        Authentication authentication;
        try {
            // 该方法会去调用VCodeUserDetailsService.loadUserByUsername
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(sysUser.getUserName(), "CUSTOM_LOGIN_SMS"));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        catch (Exception e) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, e.getMessage()));
            throw new CustomException(e.getMessage());
        }

        AsyncManager.me()
            .execute(AsyncFactory
                .recordLogininfor(phoneNumber, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser)authentication.getPrincipal();

        publishEvent.publish(WeixinLoginUserEvent.builder().sysUser(loginUser.getUser()).build());
        return new LoginSuccessVo().setToken(tokenService.createToken(loginUser)).setUser(loginUser);
    }
    
    /**
     * 找回密码
     * 
     * @param findPasswordCmd 找回密码参数
     * @return
     */
    public int findPassword(FindPasswordCmd findPasswordCmd) {
        if (!VCodeUtils.isPhoneNumber(findPasswordCmd.getPhoneNumber())) {
            throw new BaseException(MessageUtils.message("user.mobile.phone.number.not.valid"));
        }
        
        if (!findPasswordCmd.getNewPassword().trim().equals(findPasswordCmd.getConfirmPassword())) {
            throw new BaseException(MessageUtils.message("user.password.no.eq.confirmPwd"));
        }
        
        if (!VCodeUtils.checkPassword(findPasswordCmd.getNewPassword())) {
            throw new BaseException(MessageUtils.message("user.password.not.valid"));
        }
        
        SysUser sysUser = this.iSysUserService.selectUserByUserName(findPasswordCmd.getPhoneNumber());
        if (null == sysUser) {
            throw new BaseException(MessageUtils.message("user.not.exists"));
        }
        
        sysUser.setPassword(SecurityUtils.encryptPassword(findPasswordCmd.getNewPassword()));
        sysUser.setUpdateBy(sysUser.getUserId());
        return this.iSysUserService.resetPwd(sysUser);
    }
}
